/*
 * Instructions file that contains all the instructions available
 * to the BRAIN operating system.
 * 
 * instructions.c
 */

#include <stdio.h>
#include <stdlib.h>
#include "mailman.h"
#include "semaphore.h"
#include "BRAIN10.h"
#include "instructions.h"
#include "scheduler.h"

// LR
void loadRegister(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i;
    for (i = 0; i < 4; i++) 
        brain10 -> R[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
}


// LL
void loadRegLow(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i;
    for (i = 2; i < 4; i++)
        brain10 -> R[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
}


// LH
void loadRegHigh(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i;
    for (i = 0; i < 2; i++)
        brain10 -> R[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
}


// SR
void loadMemory(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i;
    char instruction[4];
    for (i = 0; i < 4; i++)
        instruction[i] = brain10 -> R[i];
    for (i = 0; i < 4; i++)
        brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i] = instruction[i];
}


// SP
void loadSPfromReg(BRAIN10 *brain10, int process)
{
    int i;
    for (i = 0; i < 4; i++)
        brain10 -> SP[i] = brain10 -> R[i];
}


// PS
void loadRfromSP(BRAIN10 *brain10, int process)
{
    int i;
    for (i = 0; i < 4; i++)
        brain10 -> R[i] = brain10 -> SP[i];
}


// PH
void push(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i;
    brain10 -> SPindx += vbrain10 -> BR[process] + 1;
    for (i = 0; i < 4; i++)
    {
        brain10 -> SP[i] = brain10 -> R[i];
        printf("Push - %d: %c\n", i, brain10 -> R[i]);
    }
    for (i = 0; i < 4; i++)
        brain10 -> storage[brain10 -> SPindx][i] = brain10 -> SP[i];
}


// PP
void pop(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i;
    for (i = 0; i < 4; i++)
        brain10 -> R[i] = brain10 -> SP[i];
    vbrain10 -> vSPIndex[process] -= vbrain10 -> BR[process] - 1;
}


// CE
void compareEqual(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i, mem, reg;
    char regist[4];
    char operand[4];
    for (i = 0; i < 4; i++)
    {
        regist[i] = brain10 -> R[i];
        operand[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    mem = atoi(operand);
    reg = atoi(regist);
    if (reg == mem)
        vbrain10 -> vC[process] = 1;
    else
        vbrain10 -> vC[process] = 0;
}


// CL
void compareLess(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i, mem, reg;
    char regis[4];
    char operand[4];
    for (i = 0; i < 4; i++)
    {
        regis[i] = brain10 -> R[i];
        operand[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    mem = atoi(operand);
    reg = atoi(regis);
    if (reg < mem)
        vbrain10 -> vC[process] = 1;
    else
        vbrain10 -> vC[process] = 0;
}


// BT
void branchConditional(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    if (vbrain10 -> vC[process] == 1)
        brain10 -> IC = wordIndex + vbrain10 -> BR[process];
}


// BU
void branchUnconditional(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    brain10 -> IC = wordIndex + vbrain10 -> BR[process];
}


// GD
void getData(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int j, k;
    //if (brain10->storage[9000+(brain10->dataLine * 10)+j][k] == '\0') {
    //    printf("ERROR!  Trying to get data that isn't there.");
    //} else {
        for (j = 0; j < 10; j++)
        {
            for (k = 0; k < 4; k++)
            {
                brain10 -> storage[wordIndex + j + vbrain10 -> BR[process]][k] = brain10 -> storage[9000+(brain10->dataLine * 10)+j][k];
            }
        }
        brain10->dataLine++;
    //}
}


// PD
void printData(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i, j;
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 4; j++)
            printf("%c", brain10 -> storage[wordIndex + i + vbrain10 -> BR[process]][j]);
        printf("\n");
    }
}


// AD
void addition(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i, reg, mem, result;
    char regist[4];
    char memory[4];
    for (i = 0; i < 4; i++)
    {
        regist[i] = brain10 -> R[i];
        memory[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    reg = atoi(regist);
    mem = atoi(memory);
    result = reg + mem;
    if (result <= 9999)
    {
        char temp[4];
        snprintf(temp, 4, "%d", result);
        for (i = 0; i < 4; i++)
            brain10 -> R[i] = temp[i];
    }
    else
        printf("Result exceeds 9999! IDKWTF2DU!.");
}


// SU
void subtraction(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
	int i, reg, mem, result;
    char regist[4];
	char memory[4];
	for (i = 0; i < 4; i++)
    {
        regist[i] = brain10 -> R[i];
		memory[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    reg = atoi(regist);
	mem = atoi(memory);
	result = reg - mem;
	if (result >= 0)
	{
		char temp[4];
		snprintf(temp, 4, "%d", result);
		for (i = 0; i < 4; i++)
			brain10 -> R[i] = temp[i];
	}
	else
		printf("Result is less than 0! IDKWTF2DU!");
}


// MU
void multiplication(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
	int i, reg, mem, result;
    char regist[4];
	char memory[4];
	for (i = 0; i < 4; i++)
    {
        regist[i] = brain10 -> R[i];
		memory[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    reg = atoi(regist);
	mem = atoi(memory);
	result = reg * mem;
	if (result >= 0)
	{
            char temp[4];
            snprintf(temp, 4, "%d", result);
            for (i = 0; i < 4; i++)
                brain10 -> R[i] = temp[i];
	}
	else
            printf("Result is less than 0! IDKWTF2DU!");
}


// DI
void division(BRAIN10 *brain10, VBRAIN10 *vbrain10, int wordIndex, int process)
{
    int i, reg, mem, result;
    char regist[4];
    char memory[4];
    for (i = 0; i < 4; i++)
    {
        regist[i] = brain10 -> R[i];
		memory[i] = brain10 -> storage[wordIndex + vbrain10 -> BR[process]][i];
    }
    
    reg = atoi(regist);
    mem = atoi(memory);
    result = reg - mem;
    if (result >= 0)
    {
        char temp[4];
        snprintf(temp, 4, "%d", result);
        for (i = 0; i < 4; i++)
            brain10 -> R[i] = temp[i];
    }
    else
        printf("Result is less than 0! IDKWTF2DU!");
}


// SA
void stackAdd(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i, s1, s2, result;
    char stack1[4];
    char stack2[4];
    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        stack1[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
    }

    brain10 -> SPindx--;

    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        brain10 -> SP[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
        stack2[i] = brain10 -> SP[i];
    }
    s1 = atoi(stack1);
    s2 = atoi(stack2);
    result = s2 + s1;
    char temp[4];
    snprintf(temp, 4, "%d", result);
    for (i = 0; i < 4; i++)
        brain10 -> SP[i] = temp[i];
}


// SS
void stackSubtract(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i, s1, s2, result;
    char stack1[4];
    char stack2[4];
    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        stack1[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
    }

    brain10 -> SPindx--;

    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        brain10 -> SP[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
        stack2[i] = brain10 -> SP[i];
    }
    s1 = atoi(stack1);
    s2 = atoi(stack2);
    result = s2 - s1;
    char temp[4];
    snprintf(temp, 4, "%d", result);
    for (i = 0; i < 4; i++)
        brain10 -> SP[i] = temp[i];
}


// SM
void stackMultiply(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i, s1, s2, result;
    char stack1[4];
    char stack2[4];
    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        stack1[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
    }

    brain10 -> SPindx--;

    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        brain10 -> SP[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
        stack2[i] = brain10 -> SP[i];
    }
    s1 = atoi(stack1);
    s2 = atoi(stack2);
    result = s2 * s1;
    char temp[4];
    snprintf(temp, 4, "%d", result);
    for (i = 0; i < 4; i++)
        brain10 -> SP[i] = temp[i];
}


// SD
void stackDivide(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i, s1, s2, result;
    char stack1[4];
    char stack2[4];
    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        stack1[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
    }

    brain10 -> SPindx--;

    for (i = 0; i < 4; i++)
    {
        int stackIndx = brain10 -> SPindx;
        brain10 -> SP[i] = brain10 -> storage[stackIndx + vbrain10 -> BR[process]][i];
        stack2[i] = brain10 -> SP[i];
    }
    s1 = atoi(stack1);
    s2 = atoi(stack2);
    result = s2 / s1;
    char temp[4];
    snprintf(temp, 4, "%d", result);
    for (i = 0; i < 4; i++)
        brain10 -> SP[i] = temp[i];
}

// NP
void noop()
{
    sleep(1);
}

// HA
void halt()
{
    exit(0);
}

//SD
void sendMsg(VBRAIN10 *vbrain10, int process, int receiveIndex, MAILMAN *mailman)
{	
    int i, j, reg;
    char regist[4];

    for (i = 0; i < 4; i++) {
        regist[i] = vbrain10 -> vR[process][i];
    }
    reg = atoi(regist);
    
    for(i=0 ; i<10 ; i++) {
        for(j=0 ; j<4 ; j++) {
            mailman -> messages[process][i][j] = vbrain10 -> vStorage[process][reg+i][j];
        }
    }

    mailman -> sProc[process][receiveIndex] = 1;
}

//RC
void receiveMsg(VBRAIN10 *vbrain10, int process, char wordIndex[], MAILMAN *mailman)
{
    int i, j, x, y, reg, proc;
    char regist[4];
    for (i = 0; i < 4; i++)
    {
        regist[i] = vbrain10 -> vR[process][i];
    }
 
    reg = atoi(regist);
 
    if(wordIndex[0] == 'X'){
        for(i=0;i<10;i++){
            if(mailman -> sProc[i][process] == 1){
               for(x=0;x<10;x++){
                    for(y=0;y<4;y++)
                        vbrain10 -> vStorage[process][reg+x][y] = mailman -> messages[i][x][y];
               }
               mailman -> sProc[i][process] = 0;
               i = 10;
            }
        }
    } else {
        proc = atoi(wordIndex);
        for (i=0;i<10;i++){
             for(j=0;j<4;j++){
                vbrain10 -> vStorage[process][reg+i][j] = mailman -> messages[proc][i][j];
             }
        }
        mailman -> sProc[proc][process] = 0;
    }
}

// GP
void processID(BRAIN10 *brain10, VBRAIN10 *vbrain10, int process)
{
    int i;
    char temp[4];
    //printf(temp, 4, "%d", process);
    for (i = 0; i < 4; i++)
        brain10 -> R[i] = temp[i];
}

// LS
void loadShared(BRAIN10 *brain10, VBRAIN10 *vbrain10, int index ,int process)
{
    int i;
    for (i = 0; i < 4; i++)
        vbrain10 -> vR[process][i] = brain10 -> storage[1000+index][i];
}

// ST
void storeShared(BRAIN10 *brain10, VBRAIN10 *vbrain10, int index ,int process)
{
    int i;
    for (i = 0; i < 4; i++)
        brain10 -> storage[1000+index][i] = vbrain10 -> vR[process][i];
}

// PE
void waitSemaphore(BRAIN10 *brain10, VBRAIN10 *vbrain10, SEMAPHORES *semaphores, int semaphore ,int process)
{
    semaphores -> state[semaphore]--;
    // Only put processes that need to wait on the wait queue
    if( semaphores -> state[semaphore] < 0 ) {
        pushProcess(semaphores, semaphore, process);
    }
}

// VE
void signalSemaphore(BRAIN10 *brain10, VBRAIN10 *vbrain10, SEMAPHORES *semaphores, int semaphore ,int process)
{
    semaphores -> state[semaphore]++;
    // Check if there are any processes waiting, then pop one off
    if( anyWaiting(semaphores, semaphore) == 1 ) {
        int ready = popProcess(semaphores, semaphore);
        pushReadyProcess(brain10, ready);
    }
}

// SI
void setSemaphore(BRAIN10 *brain10, VBRAIN10 *vbrain10, SEMAPHORES *semaphores, int semaphore ,int process)
{
    semaphores -> state[semaphore] = atoi(vbrain10 -> vR[process]);
}
